import axios from 'axios';
import xss from 'xss';
import router from '../router';
import store from '../store';
import {
  DEDAULT_REQUEST_OPTION,
  CONTENT_TYPE_MAP,
  DEDAULT_REQUEST_OPERATION,
} from '../config/request.config';
import { validURL } from '../utils/validate';
import { toast } from './tip';
const { VUE_APP_BASE_API } = process.env;

const service = axios.create({
  // axios中请求配置有baseURL选项，表示请求URL公共部分
  baseURL: VUE_APP_BASE_API,
  // 超时
  timeout: 10000,
});

let optertion = JSON.parse(JSON.stringify(DEDAULT_REQUEST_OPERATION)), isLoading = false, loadingCount = 0;

// request拦截器
service.interceptors.request.use(
  (config) => {
    const { isHasToken, contentType, loadingText } = optertion;

    // 让每个请求携带自定义token
    if (isHasToken) {
      config.headers['Authorization'] = localStorage.getItem('token') || '';
    }

    if (!isLoading && loadingCount > 0) {
      store.commit('UPDATE_LOADING', true);
      store.commit('UPDATE_LOADING_TEXT', loadingText);
    }

    config.headers['Content-Type'] = contentType;

    // 请求映射params参数
    if (config.params) {
      let url = config.url + '?' + tansParams(config.params);
      url = url.slice(0, -1);
      config.params = {};
      config.url = url;
    }
    return config;
  },
  (error) => {
    Promise.reject(error);
  }
);

// 响应拦截器
service.interceptors.response.use(
  (res) => {
    const { status, msg } = filterData(res.data),
      { fileName, isOpenPath, isAutoToastFail, } = optertion;

    // 未设置状态码则默认成功状态
    const code = status || 200;

    if (loadingCount > 0) {
      isLoading != isLoading;
      loadingCount--;
      loadingCount === 0 && store.commit('UPDATE_LOADING');
    }

    // 二进制数据
    if (
      res.request.responseType === 'blob' ||
      res.request.responseType === 'arraybuffer'
    ) {
      downLoadFile(res.data, fileName);
    }

    if (code === 200) {
      if (isOpenPath && validURL(res.data)) {
        window.open(res.data);
      }
      return Promise.resolve(res.data);
    } else {
      isAutoToastFail && toast.fail(msg);
      return Promise.reject(res.data);
    }
  },
  (error) => {
    let { message } = error,
      data = { message: '' };
    const { isAutoToastFail } = optertion;

    if (loadingCount > 0) {
      isLoading != isLoading;
      loadingCount--;
      loadingCount === 0 && store.commit('UPDATE_LOADING');
    }

    if (message == 'Network Error') {
      data.message = '服务器连接异常';
    } else if (message.includes('timeout')) {
      data.message = '请求超时';
    } else if (message.includes('401')) {
      router.push('/');
      data.message = '登录过期，请重新登录';
    } else if (message.includes('500')) {
      data.message = '服务器错误';
    } else {
      data = error.response.data;
    }
    isAutoToastFail && toast.fail(data.message);
    return Promise.reject(data);
  }
);

/**
 * @description 默认请求参数
 * @param {string} url 请求地址 - 默认("")
 * @param {string} contentType 请求头类型 JSON: json格式 FORM: form格式 FORMDATA:formData格式 - 默认(JSON)
 * @param {string} method 请求方式 - 默认(post) post put get delete
 * @param {object} data body请求数据 - 默认({})
 * @param {object} params url请求数据 - 默认({})
 * @param {function} isBackProgress 是否开启返回进度条 - 默认(false)
 * @param {function} onProgress 进度条回调函数 (val)=>{ console.log(val) } val: 进度百分比
 * @param {number} progressPrecision 进度条小数点精度
 * @param {boolean} isHasToken 是否请求带token - 默认(true)
 * @param {boolean} isAutoToastFail 是否自动提示报错 - 默认(false)
 * @param {boolean} isOpenPath 是否直接打开链接 - 默认(false)
 * @param {string} fileName 文件名称 - 默认(文件.txt)
 */
export function fetchEndpoint(option) {
  const {
    url,
    contentType,
    method,
    data = {},
    params = {},
    isBackProgress,
    onProgress,
    progressPrecision,
    isOpenPath,
    isHasToken,
    isAutoToastFail,
    loading
  } = {
    ...DEDAULT_REQUEST_OPTION,
    ...option,
  };

  optertion = {
    isOpenPath,
    isHasToken,
    isAutoToastFail,
    contentType:
      CONTENT_TYPE_MAP[contentType.toString().toUpperCase()] ||
      'application/json; charset=utf-8',

  };

  loading && loadingCount++;

  let config = {
    method,
    url,
    data: filterData(data),
    params: filterData(params),
    onDownloadProgress: (progressEvent) => {
      if (progressEvent.lengthComputable) {
        onProgress(
          ((progressEvent.loaded / progressEvent.total) * 100).toFixed(
            progressPrecision < 0 || progressPrecision > 100
              ? 2
              : progressPrecision
          )
        );
      }
    },
  };

  if (isBackProgress) delete config.onDownloadProgress;

  return service(config);
}

/**
 * @description 参数处理
 * @param {object} params  参数
 */
function tansParams(params) {
  let result = '';
  for (const propName of Object.keys(params)) {
    const value = params[propName];
    var part = encodeURIComponent(propName) + '=';
    if (value !== null && typeof value !== 'undefined') {
      if (typeof value === 'object') {
        for (const key of Object.keys(value)) {
          if (value[key] !== null && typeof value[key] !== 'undefined') {
            let params = propName + '[' + key + ']';
            var subPart = encodeURIComponent(params) + '=';
            result += subPart + encodeURIComponent(value[key]) + '&';
          }
        }
      } else {
        result += part + encodeURIComponent(value) + '&';
      }
    }
  }
  return result;
}

// 过滤和转义函数
function filterData(data) {
  if (typeof data === 'string') {
    return xss(data);
  } else if (typeof data === 'object' && data !== null) {
    for (let key in data) {
      if (typeof data[key] === 'string') {
        data[key] = xss(data[key]);
      }
    }
  }
  return data;
}

/**
 * @description 下载文件
 * @param {*} file
 * @param {*} name 名称
 * @param {*} suffix 文件
 */
function downLoadFile(file, fileName) {
  const url = window.URL.createObjectURL(new Blob([file]));
  const link = document.createElement('a');
  link.style.display = 'none';
  link.href = url;
  link.setAttribute('download', fileName);
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}
